package org.su.webadapter.velocity;

import org.su.generalmvc.annotaion.Controller;
import org.su.generalmvc.annotaion.Destroy;
import org.su.generalmvc.annotaion.Init;
import org.su.generalmvc.config.XSSHConfig;
import org.su.generalmvc.core.IXsshApplicationContext;
import org.su.generalmvc.core.InitialContext;
import org.su.generalmvc.util.ClassUtils;
import org.su.webadapter.IUserSession;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;
import org.apache.velocity.io.VelocityWriter;
import org.apache.velocity.util.SimplePool;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;


/*******************************************************************************
 * 功能：html帮助类。用于将模板生成html文件
 * TODO 这个类的代码非常乱，待整理。
 * @author yangchuan
 * 
 */
public enum  HtmlHelper {

	INSTENCE ;

	private  IXsshApplicationContext applicationContext = InitialContext.getInstance().getContext();

    private VelocityEngine ve = null;
    

    protected static final Log logger = LogFactory.getLog(HtmlHelper.class);



    private  HtmlHelper()  {
        XSSHConfig xsshConfig = applicationContext.getConfig();
		try {
			initVelocityEngine(xsshConfig, (ServletContext) applicationContext.getServiceContext().getContext());
		}catch (ServletException e){
			throw new RuntimeException(e);
		}
    }


    
    /**
     * 初始化velocity引擎
     *
     * @param xsshConfig
     * @param servletContext
     * @throws javax.servlet.ServletException
     */
    private void initVelocityEngine(XSSHConfig xsshConfig,
                                    ServletContext servletContext) throws ServletException {
        VelocityEngine vEngine = new VelocityEngine();
        vEngine.setApplicationAttribute(ServletContext.class.getName(),
                servletContext);
        try {
            String path = xsshConfig.getVelocityPath();
            if (StringUtils.isNotBlank(path)) {
                URL url = getURL(path);
                File file = new File(url.toURI());
                path = file.getAbsolutePath();
                vEngine.init(path);
            } else {
                logger.error("can't found the velocity config file with this tomcat.");
                throw new ServletException(
                        "can't found the velocity config file with this tomcat.");
                // vEngine.init(VelocityConfig.getDefualtConfig());
            }
            String encode = xsshConfig.getEncoding();
            if (!StringUtils.isNotBlank(encode)) {
                encode = "utf-8";
            }
            vEngine.setProperty(Velocity.ENCODING_DEFAULT, encode);
        } catch (Exception e) {
            throw new ServletException(e);
        }
        ve = vEngine;
    }

    private URL getURL(String path) {
        ClassLoader classLoader = ClassUtils.getDefaultClassLoader();

        URL resourceUrl = classLoader.getResource(path);
        return resourceUrl;
    }

    /**
	 * 功能：根据Map数据和模板对象生成html文件； 作者：yangchuan
	 * 
	 * @param data
	 * @param t
	 * @throws Exception
	 */
	public  void generateHtml(Map<String, ?> data, Template t,
			ServletRequest request, ServletResponse response)
			throws Exception {
		VelocityContext context = new VelocityContext(data);
		initContext(context, request);
		mergeTemplate(t, context, response);
	}

	/**
	 * 通过普通Object生成html数据
	 * 
	 * @param data
	 * @param t
	 * @param request
	 * @param response
	 * @throws Exception
	 */
	public  void generateHtml(Object data, Template t,
			ServletRequest request, ServletResponse response)
			throws Exception {
		VelocityContext context = new VelocityContext();
		initContext(context, request);
		context.put("sshObject", data);
		mergeTemplate(t, context, response);
	}

	/**
	 * 初始一些值到Velocity环境
	 * 
	 * @param context
	 */
	private  void initContext(VelocityContext context,
			ServletRequest request) {
        HttpServletRequest hr = (HttpServletRequest)request;
		context.put("sysBasePath", getBasePath(hr));

		context.put("applicationContext", applicationContext);
		context.put("sshUtil", VelocityUtils.getInstance());
		context.put("request", request);
		context.put("s_user",hr.getSession().getAttribute(IUserSession.USER_SESSION));
		context.put("VH", VelocityUtils.getInstance());
	}

	public  String getBasePath(HttpServletRequest request) {
		String serverName = request.getServerName();
		String result = null;
		
		if (request.getServerPort() == 80) {
			result = request.getScheme() + "://" + serverName + request.getContextPath() + "/";
			
		} else {
			result = request.getScheme() + "://" + serverName + ":"
				+ request.getServerPort() + request.getContextPath() + "/";
		}

		return result;
	}

	/**
	 * 功能：根据数据，模板路径，模板文件名称 作者：yangchuan
	 * 
	 * @param data
	 * @param path
	 * @param path
	 * @throws Exception
	 */
	public  void generateHtml(Map<String, ?> data, String path,
			ServletRequest request, ServletResponse response) {
		Template t;
		try {
			t = ve.getTemplate(path);
			generateHtml(data, t, request, response);
		} catch (Exception e) {
			throw new HtmlGenerateException(e);
		}
	}

	public  void generateHtml(Object data, String path,
			ServletRequest request, ServletResponse response) {
		Template t;
		try {
			t = ve.getTemplate(path);
			generateHtml(data, t, request, response);
		} catch (Exception e) {
			throw new HtmlGenerateException(e);
		}
	}

	/**
	 * 产生html字符串
	 * 
	 * @param data
	 * @param path
	 * @return
	 * @throws Exception
	 */
	public  String generateHtml(Map<String, ?> data, String path) {
		Template t;
		StringWriter writer = null;
		try {
			t = ve.getTemplate(path);
			VelocityContext context = new VelocityContext(data);
			context.put("VH", VelocityUtils.getInstance());
			writer = new StringWriter();
			t.merge(context, writer);
			return writer.toString();
		} catch (Exception e) {
			throw new HtmlGenerateException(e);
		}
	}

	/***************************************************************************
	 * 将模板输出为文件
	 * 
	 * @param data
	 *            模板数据
	 * @param srcPath
	 *            模板路径
	 * @param decPath
	 *            目标文件路径
	 * @throws Exception
	 */
	public  void generateFile(Map<String, ?> data, String srcPath,
			String decPath) throws Exception {
		generateFile(data, null, srcPath, decPath);
	}

	/**
	 * 将模板输出为文件
	 * 
	 * @param data
	 *            模板数据
	 * @param request
	 * @param srcPath
	 *            模板路径
	 * @param decPath
	 *            目标文件路径
	 * @throws Exception
	 */
	public  void generateFile(Map<String, ?> data,
			ServletRequest request, String srcPath, String decPath)
			throws Exception {
		File file = new File(decPath);
		File parent = file.getParentFile();
		if (!parent.exists()) {
			if (!parent.mkdirs()) {
				throw new FileNotFoundException(file.getAbsolutePath());
			}
		}

		Template t = ve.getTemplate(srcPath);
		VelocityContext context = new VelocityContext(data);
		if (request != null) {
			initContext(context, request);
		}
		

		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
				new FileOutputStream(file), applicationContext.getConfig().getEncoding()));
		try {
			t.merge(context, writer);
		} finally {
			writer.close();
		}
	}
	
	private  SimplePool writerPool = new SimplePool(40);
	/**
	 * 将模板输出为文件
	 * 
	 * @param file
	 *            要输出的文件
	 * @param data
	 *            模板需要的数据
	 * @param templateStr
	 *            模板内容字符串
	 * @throws Exception
	 */
	public  void writeHtml(File file, Map<String, ?> data,
			String templateStr) throws Exception {
		
		FileOutputStream output = new FileOutputStream(file);
		String encode = applicationContext.getConfig().getEncoding();
		String log = file.getName();
		if (data == null) {
			data = new HashMap<String, Object>();
		}
		VelocityContext context = new VelocityContext(data);
		context.put("VH", VelocityUtils.getInstance());
		VelocityWriter vw = (VelocityWriter) writerPool.get();
		if (vw == null) {
			vw = new VelocityWriter(new OutputStreamWriter(output, encode),
					4 * 1024, true);
		} else {
			vw.recycle(new OutputStreamWriter(output, encode));
		}
		ve.evaluate(context, vw, log, templateStr);
		if (vw != null) {
			vw.flush();
			vw.recycle(null);
			writerPool.put(vw);
		}
	}

	
	/**
	 * 通过模板字串生成html字串
	 * @param data 模型数据
	 * @param templateStr 模型字串
	 * @param vmlog velocity日志标示
	 * @return
	 * @throws Exception
	 */
	public  String writeHtml(Map<String, ?> data,
			String templateStr,String vmlog) throws Exception {
		
		StringWriter sw = new StringWriter();
		//String encode = applicationContext.getConfig().getEncoding();
		if (data == null) {
			data = new HashMap<String, Object>();
		}
		VelocityContext context = new VelocityContext(data);
		context.put("VH", VelocityUtils.getInstance());
		VelocityWriter vw = (VelocityWriter) writerPool.get();
		if (vw == null) {
			vw = new VelocityWriter(sw,
					4 * 1024, true);
		} else {
			vw.recycle(sw);
		}
		ve.evaluate(context, vw, vmlog, templateStr);
		if (vw != null) {
			vw.flush();
			vw.recycle(null);
			writerPool.put(vw);
		}
		return sw.toString();
	}

	/**
	 * 本方法参考VelocityServlet.mergeTemplate
	 * 
	 */
	protected  void mergeTemplate(Template template, Context context,
			ServletResponse response) throws IOException {

		Writer vm = response.getWriter();
		try {
			template.merge(context, vm);
		} finally {
			vm.close();
		}
	}

}
